package zom.zenjava.zendeploy.gui.swing;

import zom.zenjava.zendeploy.ZenDeployException;
import zom.zenjava.zendeploy.ZenDeployManager;
import zom.zenjava.zendeploy.model.ApplicationProfile;
import zom.zenjava.zendeploy.model.CheckForUpdateResult;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ApplicationUpdateWizard extends JPanel
{
    private final static Logger LOGGER = Logger.getLogger(ApplicationUpdateWizard.class.getName());

    private static final String APP_PROFILE = "appProfile";
    private static final String MESSAGE = "message";

    private CardLayout cardLayout;
    private JLabel messageLabel;
    private JProgressBar progressBar;
    private JLabel appProfileMessageLabel;
    private ApplicationProfileView appProfileView;
    private JButton updateButton;
    
    public ApplicationUpdateWizard()
    {
        buildView();
    }
    
    public void checkForUpdates()
    {
        showLoading("Checking for updates");
        CheckForUpdatesWorker worker = new CheckForUpdatesWorker();
        worker.execute();
    }

    public void upgradeToLatestApplicationProfile()
    {
        showLoading("Updating to latest version");
        InstallUpdateWorker worker = new InstallUpdateWorker();
        worker.execute();
    }

    protected void showLoading(String loadingMessage)
    {
        messageLabel.setText(loadingMessage);
        progressBar.setVisible(true);
        progressBar.setIndeterminate(true);
        cardLayout.show(this, MESSAGE);
    }
    
    protected void showMessage(String message)
    {
        messageLabel.setText(message);
        progressBar.setVisible(false);
        cardLayout.show(this, MESSAGE);
    }
    
    protected void showError(String message, Throwable error)
    {
        messageLabel.setText(String.format("%s: %s", message, error.getMessage()));
        progressBar.setVisible(false);
        cardLayout.show(this, MESSAGE);
    }
    
    protected void showApplicationProfile(String message, ApplicationProfile appProfile)
    {
        appProfileMessageLabel.setText(message);
        appProfileView.setAppProfile(appProfile);
        cardLayout.show(this, APP_PROFILE);
    }

    
    private void buildView()
    {
        cardLayout = new CardLayout();
        setLayout(cardLayout);
        
        add(MESSAGE, buildMessageArea());
        add(APP_PROFILE, buildAppProfileArea());

        showMessage(null);
    }

    private JPanel buildMessageArea()
    {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setOpaque(false);
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.fill = GridBagConstraints.NONE;
        gbc.insets = new Insets(10, 10, 10, 10);

        messageLabel = new JLabel();
        gbc.gridy = 0;
        panel.add(messageLabel, gbc);
        
        progressBar = new JProgressBar();
        gbc.gridy++;
        panel.add(progressBar, gbc);
        
        gbc.gridy++;
        gbc.weighty = 1;
        panel.add(Box.createVerticalGlue(), gbc);
        
        return panel;
    }
    
    private JPanel buildAppProfileArea()
    {
        JPanel panel = new JPanel(new BorderLayout(10, 10));
        panel.setOpaque(false);

        appProfileMessageLabel = new JLabel("", JLabel.CENTER);
        panel.add(appProfileMessageLabel, BorderLayout.NORTH);
        
        appProfileView = new ApplicationProfileView();
        appProfileView.setOpaque(false);
        panel.add(appProfileView, BorderLayout.CENTER);
        
        updateButton = new JButton("Update Now");
        updateButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                upgradeToLatestApplicationProfile();
            }
        });
        JPanel aligner = new JPanel(new FlowLayout(FlowLayout.CENTER));
        aligner.setOpaque(false);
        aligner.add(updateButton);
        panel.add(aligner, BorderLayout.SOUTH);
        
        return panel;
    }

    //-------------------------------------------------------------------------
    
    private class CheckForUpdatesWorker extends SwingWorker<CheckForUpdateResult, Void>
    {
        protected CheckForUpdateResult doInBackground() throws Exception
        {
            ZenDeployManager zenDeployManager = ZenDeployManager.getInstance();
            return zenDeployManager.checkForUpdatedApplicationProfile();
        }

        protected void done()
        {
            try
            {
                CheckForUpdateResult result = get();
                if (result.getUpdatedApplicationProfile() != null)
                {
                    showApplicationProfile("A newer version is available", result.getUpdatedApplicationProfile());
                }
                else
                {
                    showApplicationProfile("You already have the most up to date version", result.getCurrentApplicationProfile());
                }
            }
            catch (InterruptedException e)
            {
                LOGGER.warning("Check for updates thread was interrupted");
                showError("Check for updates was interrupted", null);
            }
            catch (ExecutionException e)
            {
                LOGGER.log(Level.SEVERE, "Error while checking for updates", e.getCause());
                showError("An error occurred while checking for updates", e.getCause());
            }
        }
    }

    //-------------------------------------------------------------------------

    private class InstallUpdateWorker extends SwingWorker<Boolean, Void>
    {
        private ZenDeployManager zenDeployManager;

        protected Boolean doInBackground() throws Exception
        {
            zenDeployManager = ZenDeployManager.getInstance();
            return zenDeployManager.upgradeToLatestApplicationProfile();
        }

        protected void done()
        {
            try
            {
                Boolean isRestartNeeded = get();
                showMessage("Update complete!");
                if (isRestartNeeded)
                {
                    JOptionPane.showMessageDialog(getTopLevelAncestor(), "Update complete - time to restart");
                    try
                    {
                        zenDeployManager.restart();
                    }
                    catch (ZenDeployException e)
                    {
                        e.printStackTrace();
                        JOptionPane.showMessageDialog(getTopLevelAncestor(), "Unable to restart - you'll have to do it yourself");
                    }
                }
            }
            catch (InterruptedException e)
            {
                LOGGER.warning("Update download and installation thread was interrupted");
                showError("Update download and installation was interrupted", null);
            }
            catch (ExecutionException e)
            {
                LOGGER.log(Level.SEVERE, "Error while downloading and installing application update", e.getCause());
                showError("Error while downloading and installing application update", e.getCause());
            }
        }
    }
}
